
#pragma once

#include <cmath>

#include "Transformations.h"
#include "DCoordinates.h"

namespace cagd
{
	//----------
	// translate
	//----------
	class CTranslate: public CTransformation
	{
	public:
		CTranslate(float ux, float uy, float uz): CTransformation()
		{
			matrix[12] = ux;
			matrix[13] = uy;
			matrix[14] = uz;
		}

		// vector "direction" will be normalized
                // so, do not declare variable "direction" as "const DCoordinate &"
                CTranslate(DCoordinate &direction, float distance): CTransformation()
		{
			direction.Normalize();
			matrix[12] = direction.x * distance;
			matrix[13] = direction.y * distance;
			matrix[14] = direction.z * distance;
		}

		CTranslate(const CTranslate &translation): CTransformation(translation)
		{
		}

		CTranslate& operator = (const CTranslate &translation)
		{
			if (this != &translation)
				CTransformation::operator = (translation);
			return *this;
		}
	};

	//------
	// scale
	//------
	class CScale: public CTransformation
	{
	public:
		CScale(float sx, float sy, float sz);
		CScale(const CScale &scale);
		CScale& operator = (const CScale &scale);
	};

	//-------
	// rotate
	//-------
	class CRotate: public CTransformation
	{
	public:

		// vector "direction" will be normalized
                // so, do not declare variable "direction" as "const DCoordinate &"
		// rotation R will correspond to unit axis "direction" and "angleInRadians"
		//
		// we will use the formula:
		// R = I + sin(angleInRadians) * S + (1.0f - cos(angleInRadians)) * S2
		//
		// where
		//
		// I is the identity matrix,
		//
		// S = (0				direction.z		-direction.y
		//      -direction.z	0				direction.x
		//		direction.y		-direction.x	0			)
		//
		// is a skew-symmetric matrix and
		//
		// S2 = S * S
                CRotate(DCoordinate &direction, float angleInRadians)
		{
			direction.Normalize();

			CTransformation I, S;

			S.LoadNullMatrix();
			S.matrix[4] =  direction.z;
			S.matrix[8] = -direction.y;
			S.matrix[1] = -direction.z;
			S.matrix[9] =  direction.x;
			S.matrix[2] =  direction.y;
			S.matrix[6] = -direction.x;

			CTransformation S2 = S * S;

			LoadNullMatrix();
			S  *= sin(angleInRadians);
			S2 *= 1.0f - cos(angleInRadians);
			*this += I;
			*this += S;
			*this += S2;
		}

		CRotate(const CRotate &rotate);
		CRotate& operator = (const CRotate &rotate);
	};
}
